/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package org.python.pydev.navigator.actions.copied;
import java.io.ByteArrayInputStream;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.CopyFilesAndFoldersOperation;
import org.eclipse.ui.actions.CopyProjectOperation;
import org.eclipse.ui.actions.SelectionListenerAction;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.ResourceTransfer;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.actions.PyAction;
/**
* Copied to extend.
*
* @since 2.0
*/
public abstract class PasteAction extends SelectionListenerAction {
/**
* The id of this action.
*/
public static final String ID = PlatformUI.PLUGIN_ID + ".PasteAction";//$NON-NLS-1$
/**
* The shell in which to show any dialogs.
*/
private Shell shell;
/**
* System clipboard
*/
private Clipboard clipboard;
/**
* Creates a new action.
*
* @param shell the shell for any dialogs
* @param clipboard the clipboard
*/
public PasteAction(Shell shell, Clipboard clipboard) {
super("Paste"); // TODO ResourceNavigatorMessages.PasteAction_title); //$NON-NLS-1$
Assert.isNotNull(shell);
Assert.isNotNull(clipboard);
this.shell = shell;
this.clipboard = clipboard;
setToolTipText("Paste ToolTip"); // TODO ResourceNavigatorMessages.PasteAction_toolTip); //$NON-NLS-1$
setId(PasteAction.ID);
// PlatformUI.getWorkbench().getHelpSystem().setHelp(this, "HelpId"); //$NON-NLS-1$
// TODO INavigatorHelpContextIds.PASTE_ACTION);
}
/**
* Returns the actual target of the paste action. Returns null
* if no valid target is selected.
*
* @return the actual target of the paste action
*/
private IResource getTarget() {
List selectedResources = getSelectedResources();
for (int i = 0; i < selectedResources.size(); i++) {
IResource resource = (IResource) selectedResources.get(i);
if (resource instanceof IProject && !((IProject) resource).isOpen()) {
return null;
}
if (resource.getType() == IResource.FILE) {
resource = resource.getParent();
}
if (resource != null) {
return resource;
}
}
return null;
}
/**
* Returns whether any of the given resources are linked resources.
*
* @param resources resource to check for linked type. may be null
* @return true=one or more resources are linked. false=none of the
* resources are linked
*/
private boolean isLinked(IResource[] resources) {
for (int i = 0; i < resources.length; i++) {
if (resources[i].isLinked()) {
return true;
}
}
return false;
}
/**
* Implementation of method defined on <code>IAction</code>.
*/
public void run() {
// try a resource transfer
ResourceTransfer resTransfer = ResourceTransfer.getInstance();
IResource[] resourceData = (IResource[]) clipboard.getContents(resTransfer);
if (resourceData != null && resourceData.length > 0) {
if (resourceData[0].getType() == IResource.PROJECT) {
// enablement checks for all projects
for (int i = 0; i < resourceData.length; i++) {
CopyProjectOperation operation = new CopyProjectOperation(this.shell);
operation.copyProject((IProject) resourceData[i]);
}
} else {
// enablement should ensure that we always have access to a container
IContainer container = getContainer();
CopyFilesAndFoldersOperation operation = new CopyFilesAndFoldersOperation(this.shell);
operation.copyResources(resourceData, container);
}
return;
}
// try a file transfer
FileTransfer fileTransfer = FileTransfer.getInstance();
String[] fileData = (String[]) clipboard.getContents(fileTransfer);
if (fileData != null) {
// enablement should ensure that we always have access to a container
IContainer container = getContainer();
CopyFilesAndFoldersOperation operation = new CopyFilesAndFoldersOperation(this.shell);
operation.copyFiles(fileData, container);
return;
}
//Now, at last, try a text transfer (create a new file with the contents).
TextTransfer instance = TextTransfer.getInstance();
String contents = (String) clipboard.getContents(instance);
if (contents != null) {
// enablement should ensure that we always have access to a container
IContainer container = getContainer();
String name = getNameForContentsPasted(container);
if (name == null) {
return;
}
String delimiter = PyAction.getDelimiter(new Document());
if (delimiter != null) {
StringUtils.replaceNewLines(contents, delimiter);
}
IFile file = container.getFile(new Path(name));
if (!file.exists()) {
try {
file.create(new ByteArrayInputStream(contents.getBytes()), true, null);
} catch (CoreException e) {
Log.log(e);
}
try {
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
if (page != null) {
IDE.openEditor(page, file);
}
} catch (Exception e) {
Log.log(e);
}
}
}
}
private String getNameForContentsPasted(final IContainer container) {
final IWorkspace workspace = container.getWorkspace();
final String returnValue[] = { null };
final IInputValidator validator = new IInputValidator() {
public String isValid(String string) {
IStatus status = workspace.validateName(string, IResource.FILE);
if (!status.isOK()) {
return status.getMessage();
}
if (container.getFile(new Path(string)).exists()) {
return "File already exists";
}
return null;
}
};
String base = "snippet%s.py";
for (int i = 0; i < 1000; i++) {
String newCheck;
if (i == 0) {
newCheck = com.aptana.shared_core.string.StringUtils.format(base, "");
} else {
newCheck = com.aptana.shared_core.string.StringUtils.format(base, i);
}
if (validator.isValid(newCheck) == null) {
base = newCheck;
break;
}
}
final String initialValue = base;
this.shell.getDisplay().syncExec(new Runnable() {
public void run() {
InputDialog dialog = new InputDialog(shell, "Enter file name",
"Please enter the name of the file to be created with the pasted contents.", initialValue,
validator) {
@Override
protected void createButtonsForButtonBar(Composite parent) {
super.createButtonsForButtonBar(parent);
Text control = getText();
String textInControl = control.getText();
int i = textInControl.indexOf('.');
if (i >= 0) {
control.setSelection(0, i);
}
}
};
dialog.setBlockOnOpen(true);
dialog.open();
if (dialog.getReturnCode() == Window.CANCEL) {
returnValue[0] = null;
} else {
returnValue[0] = dialog.getValue();
}
}
});
if (returnValue[0] == null) {
return null;
}
return returnValue[0];
}
/**
* Returns the container to hold the pasted resources.
*/
private IContainer getContainer() {
List selection = getSelectedResources();
if (selection.get(0) instanceof IFile) {
return ((IFile) selection.get(0)).getParent();
}
return (IContainer) selection.get(0);
}
/**
* The <code>PasteAction</code> implementation of this
* <code>SelectionListenerAction</code> method enables this action if
* a resource compatible with what is on the clipboard is selected.
*
* -Clipboard must have IResource or java.io.File
* -Projects can always be pasted if they are open
* -Workspace folder may not be copied into itself
* -Files and folders may be pasted to a single selected folder in open
* project or multiple selected files in the same folder
*/
protected boolean updateSelection(IStructuredSelection selection) {
if (!super.updateSelection(selection)) {
return false;
}
final IResource[][] clipboardData = new IResource[1][];
shell.getDisplay().syncExec(new Runnable() {
public void run() {
// clipboard must have resources or files
ResourceTransfer resTransfer = ResourceTransfer.getInstance();
clipboardData[0] = (IResource[]) clipboard.getContents(resTransfer);
}
});
IResource[] resourceData = clipboardData[0];
boolean isProjectRes = resourceData != null && resourceData.length > 0
&& resourceData[0].getType() == IResource.PROJECT;
if (isProjectRes) {
for (int i = 0; i < resourceData.length; i++) {
// make sure all resource data are open projects
// can paste open projects regardless of selection
if (resourceData[i].getType() != IResource.PROJECT || ((IProject) resourceData[i]).isOpen() == false) {
return false;
}
}
return true;
}
if (getSelectedNonResources().size() > 0) {
return false;
}
IResource targetResource = getTarget();
// targetResource is null if no valid target is selected (e.g., open project)
// or selection is empty
if (targetResource == null) {
return false;
}
// can paste files and folders to a single selection (file, folder,
// open project) or multiple file selection with the same parent
List selectedResources = getSelectedResources();
if (selectedResources.size() > 1) {
for (int i = 0; i < selectedResources.size(); i++) {
IResource resource = (IResource) selectedResources.get(i);
if (resource.getType() != IResource.FILE) {
return false;
}
if (!targetResource.equals(resource.getParent())) {
return false;
}
}
}
if (resourceData != null) {
// linked resources can only be pasted into projects
if (isLinked(resourceData) && targetResource.getType() != IResource.PROJECT) {
return false;
}
if (targetResource.getType() == IResource.FOLDER) {
// don't try to copy folder to self
for (int i = 0; i < resourceData.length; i++) {
if (targetResource.equals(resourceData[i])) {
return false;
}
}
}
return true;
}
TransferData[] transfers = clipboard.getAvailableTypes();
FileTransfer fileTransfer = FileTransfer.getInstance();
for (int i = 0; i < transfers.length; i++) {
if (fileTransfer.isSupportedType(transfers[i])) {
return true;
}
}
return false;
}
}